package com.ve.clexer;

public class WordBuffer {
    public final static int UNKNOW = 0;//无
    public final static int NUMBER = 1;//数字
    public final static int CHAR = 2;//字符
    public final static int SYMBOL = 3;//符号
    public final static int SPACE = 4;//符号
    private char[] buffer;
    private int length;
    private int position, row;
    private WordType wordType = WordType.SPACE;

    public WordBuffer() {
        buffer = new char[128];
    }

    public int length() {
        return length;
    }


    public Word analyse(int index, int row, char c) {
        if (length == 0) {
            analyseFirstChar(index, row, c);
            return null;
        }

        int ntype = typeOfChar(c);


        switch (wordType) {
            case UNKNOW:
                if (ntype != UNKNOW) {
                    return finishWithoutCurrent(index, row, c);
                }
                break;
            case NUMBER:
                if (ntype != NUMBER && ntype != CHAR && c != '.') {
                    return finishWithoutCurrent(index, row, c);
                }
                break;
            case OPERATOR:
                if (buffer[length - 1] == '/') {
                    if (c == '*') {
                        wordType = WordType.ANNOTATION_AREA;
                        break;
                    } else if (c == '/') {
                        wordType = WordType.ANNOTATION_LINE;
                        break;
                    }

                }
                return finishWithoutCurrent(index, row, c);
            case SPACE:
                if (ntype != SPACE) {
                    return finishWithoutCurrent(index, row, c);
                }
                break;
            case ANNOTATION_AREA:
                if (buffer[length - 1] == '*' && c == '/') {
                    return finishWithCurrent(c);
                }
                break;
            case ANNOTATION_LINE:
                if (c == CLanguage.NEWLINE || c == CLanguage.EOF) {
                    return finishWithCurrent(c);
                }
                break;
            case IDENTIFIER:
                if (ntype!=CHAR&&ntype!=NUMBER){
                    return finishWithoutCurrent(index, row, c);
                }
                break;
            case CHARACTER:
                if (c=='\''&&buffer[length - 1] != '\\' ){
                    return finishWithCurrent(c);
                }
                break;
            case STRING:
                if (c=='\"'&&buffer[length - 1] != '\\' ){
                    return finishWithCurrent(c);
                }
                break;
        }

        pushc(c);
        return null;
    }

    private void pushc(char c) {
        buffer[length++] = c;
    }

    private WordType guessWordType(char c) {
        switch (c) {
            case '\'':
                return WordType.CHARACTER;
            case '"':
                return WordType.STRING;
        }
        switch (typeOfChar(c)) {
            case NUMBER:
                return WordType.NUMBER;
            case CHAR:
                return WordType.IDENTIFIER;
            case SPACE:
                return WordType.SPACE;
            case SYMBOL:
                return WordType.OPERATOR;
            case UNKNOW:
            default:
                return WordType.UNKNOW;
        }
    }

    private void analyseFirstChar(int index, int row, char c) {
        this.position = index;
        this.row = row;
        wordType = guessWordType(c);
        pushc(c);
    }

    public Word finishNow() {
        Word w = new Word(position, this.row, String.valueOf(buffer, 0, length), wordType);
        this.length = 0;
        wordType=WordType.UNKNOW;
        return w;
    }

    private Word finishWithCurrent(char c) {
        pushc(c);
        return finishNow();
    }

    private Word finishWithoutCurrent(int index, int row, char c) {
        Word w = new Word(position, this.row, String.valueOf(buffer, 0, length), wordType);
        this.length = 0;
        analyseFirstChar(index, row, c);
        return w;
    }

    public static int typeOfChar(char c) {
        int ascii = c;
        if (CLanguage.isWhitespace(c)) {
            return SPACE;
        } else if (c == '_') {
            return CHAR;
        } else if (ascii < 33) {
            return UNKNOW;
        } else if (ascii < 48) {
            return SYMBOL;
        } else if (ascii < 58) {
            return NUMBER;
        } else if (ascii < 65) {
            return SYMBOL;
        } else if (ascii < 91) {
            return CHAR;//大写
        } else if (ascii < 97) {
            return SYMBOL;
        } else if (ascii < 123) {
            return CHAR;//小写
        } else if (ascii < 127) {
            return SYMBOL;
        }

        return UNKNOW;
    }
}